package com.tools.generator.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.tools.common.exception.ToolException;
import com.tools.common.utils.DateUtils;
import com.tools.generator.config.GeneratorConfig;
import com.tools.generator.entity.BaseClassEntity;
import com.tools.generator.entity.TableEntity;
import com.tools.generator.entity.TableFieldEntity;
import com.tools.generator.entity.template.GeneratorInfo;
import com.tools.generator.entity.template.TemplateInfo;
import com.tools.generator.entity.vo.PreviewVo;
import com.tools.generator.service.*;
import com.tools.generator.utils.TemplateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@Slf4j
@Service
public class GeneratorServiceImpl implements GeneratorService {

    @Autowired
    private DataSourceService datasourceService;
    @Autowired
    private FieldTypeService fieldTypeService;
    @Autowired
    private BaseClassService baseClassService;
    @Autowired
    private GeneratorConfig generatorConfig;
    @Autowired
    private TableService tableService;
    @Autowired
    private TableFieldService tableFieldService;

    @Override
    public void downloadCode(Long tableId, ZipOutputStream zip) {
        // 数据模型
        Map<String, Object> dataModel = getDataModel(tableId);
        // 代码生成器信息
        GeneratorInfo generator = generatorConfig.getGeneratorConfig();
        //设置velocity资源加载器
        VelocityEngine velocityEngine = new VelocityEngine();
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        // 获取所有模板路径
        List<TemplateInfo> templates = generator.getTemplates();

        VelocityContext context = new VelocityContext(dataModel);
        for (TemplateInfo template : templates) {
            dataModel.put("templateName", template.getTemplateName());
            String templatePaths = template.getTemplatePaths();
            String content = TemplateUtils.getTemplateContent(templatePaths, context);
            String generatorPath = template.getGeneratorPath();

            String path = TemplateUtils.fillTemplateContent(velocityEngine, context, generatorPath);
            try {
                // 添加到zip
                zip.putNextEntry(new ZipEntry(path));
                IoUtil.writeUtf8(zip, false, content);
                zip.flush();
                zip.closeEntry();
            } catch (IOException e) {
                throw new ToolException("模板写入失败：" + path, e);
            }
        }
    }

    @Override
    public void generatorCode(Long tableId) {
        // 数据模型
        Map<String, Object> dataModel = getDataModel(tableId);
        // 代码生成器信息
        GeneratorInfo generator = generatorConfig.getGeneratorConfig();
        //设置velocity资源加载器
        VelocityEngine velocityEngine = new VelocityEngine();
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        // 获取所有模板路径
        List<TemplateInfo> templates = generator.getTemplates();

        VelocityContext context = new VelocityContext(dataModel);
        for (TemplateInfo template : templates) {
            dataModel.put("templateName", template.getTemplateName());
            String templatePaths = template.getTemplatePaths();
            String content = TemplateUtils.getTemplateContent(templatePaths, context);
            String generatorPath = template.getGeneratorPath();

            String path = TemplateUtils.fillTemplateContent(velocityEngine, context, generatorPath);
            FileUtil.writeUtf8String(content,path);
        }
    }

    @Override
    public List<PreviewVo> preview(Long tableId) {
        GeneratorInfo genConfig = generatorConfig.getGeneratorConfig();
        Map<String, Object> dataModel = getDataModel(tableId);
        //设置velocity资源加载器
        Properties prop = new Properties();
        prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(prop);
        VelocityContext context = new VelocityContext(dataModel);

        // 获取所有模板路径
        List<TemplateInfo> templates = genConfig.getTemplates();
        return templates.stream().map(item -> {
            // 如果使用的模板引擎是freemarker 则用模板内容生成
            String templateContent = item.getTemplateContent();
            String templateName = item.getTemplateName();

            //如果用的是 Velocity 则用模板路径
            String templatePaths = item.getTemplatePaths();
            String content = TemplateUtils.getTemplateContent(templatePaths, context);
            return new PreviewVo(templateName, content);
        }).collect(Collectors.toList());
    }

    /**
     * 获取模型数据
     *
     * @param tableId 表ID
     * @return 模型数据
     */
    private Map<String, Object> getDataModel(Long tableId) {
        // 表信息 和 字段信息
        TableEntity table = tableService.getById(tableId);
        List<TableFieldEntity> fieldList = tableFieldService.getByTableId(tableId);
        table.setFieldList(fieldList);

        // 获取数据库类型
        String dbType = datasourceService.getDatabaseProductName(table.getDatasourceId());

        // 数据模型
        Map<String, Object> dataModel = new HashMap<>(16);
        dataModel.put("dbType", dbType);

        // 项目信息
        dataModel.put("package", table.getPackageName());
        dataModel.put("packagePath", table.getPackageName().replace(".", File.separator));
        dataModel.put("version", table.getVersion());
        dataModel.put("moduleName", table.getModuleName());
        dataModel.put("ModuleName", StrUtil.upperFirst(table.getModuleName()));
        dataModel.put("functionName", table.getFunctionName());
        dataModel.put("FunctionName", StrUtil.upperFirst(table.getFunctionName()));
        dataModel.put("formLayout", table.getFormLayout());

        // 开发者信息
        dataModel.put("author", table.getAuthor());
        dataModel.put("email", table.getEmail());
        dataModel.put("datetime", DateUtils.getDateStr(DateUtils.DATE_TIME_PATTERN));
        dataModel.put("date", DateUtils.getDateStr(DateUtils.DATE_PATTERN));

        // 表信息
        dataModel.put("tableName", table.getTableName());
        dataModel.put("tableComment", table.getTableComment());
        dataModel.put("className", StrUtil.lowerFirst(table.getClassName()));
        dataModel.put("ClassName", table.getClassName());
        dataModel.put("fieldList", table.getFieldList());

        // 生成路径
        dataModel.put("backendPath", table.getBackendPath());
        dataModel.put("frontendPath", table.getFrontendPath());

        // 导入的包列表
        Set<String> importList = fieldTypeService.getPackageByTableId(table.getId());
        dataModel.put("importList", importList);

        // 设置字段分类
        setFieldTypeList(dataModel, table);

        // 设置基类信息
        setBaseClass(dataModel, table);
        return dataModel;
    }

    /**
     * 设置基类信息
     *
     * @param dataModel 数据模型
     * @param table     表对象
     */
    private void setBaseClass(Map<String, Object> dataModel, TableEntity table) {
        if (table.getBaseclassId() == null) {
            return;
        }
        // 基类
        BaseClassEntity baseClass = baseClassService.getById(table.getBaseclassId());
        baseClass.setPackageName(baseClass.getPackageName());
        dataModel.put("baseClass", baseClass);

        // 基类字段
        String[] fields = baseClass.getFields().split(",");

        // 标注为基类字段
        for (TableFieldEntity field : table.getFieldList()) {
            if (ArrayUtil.contains(fields, field.getFieldName())) {
                field.setBaseField(true);
            }
        }
    }

    /**
     * 设置字段分类
     *
     * @param dataModel 数据模型
     * @param table     表对象
     */
    private void setFieldTypeList(Map<String, Object> dataModel, TableEntity table) {
        // 主键列表 (支持多主键)
        List<TableFieldEntity> primaryList = new ArrayList<>();
        // 表单列表
        List<TableFieldEntity> formList = new ArrayList<>();
        // 网格列表
        List<TableFieldEntity> gridList = new ArrayList<>();
        // 查询列表
        List<TableFieldEntity> queryList = new ArrayList<>();
        for (TableFieldEntity field : table.getFieldList()) {
            if (field.isPrimaryPk()) {
                primaryList.add(field);
            }
            if (field.isFormItem()) {
                formList.add(field);
            }
            if (field.isGridItem()) {
                gridList.add(field);
            }
            if (field.isQueryItem()) {
                queryList.add(field);
            }
        }
        dataModel.put("primaryList", primaryList);
        dataModel.put("formList", formList);
        dataModel.put("gridList", gridList);
        dataModel.put("queryList", queryList);
    }
}
